feat: auto-strip thinking blocks from generations before scoring#1380
Open
Luodian wants to merge 2 commits into
Open
feat: auto-strip thinking blocks from generations before scoring#1380Luodian wants to merge 2 commits into
Luodian wants to merge 2 commits into
Conversation
…ring (TaskConfig.auto_strip_thinking)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
StripThinkingFilter(lmms_eval/filters/transformation.py) that strips<think>...</think>/<thinking>...</thinking>reasoning blocks from model generations, delegating to the existinglmms_eval.api.reasoning.strip_reasoning_tagshelper. Handles both full tag pairs and the common chat-template case where only the closing tag appears in the completion (opening tag was prefilled into the prompt).FILTER_REGISTRYas"strip_thinking".TaskConfig.auto_strip_thinking: bool = False— strictly opt-in per task (or via task overrides), so scoring inputs for existing tasks/users are bit-identical by default.evaluator.evaluate(), when a task enables it,StripThinkingFilteris inserted at the front of each of the task's existing filter pipelines — chained, so the answer-extraction filters (take_first, regex, multi-choice) actually receive the stripped text, and no extra scored filter key is created. Auto-strip is skipped when the task/CLI already configuresreasoning_tags, which strips at scoring time — running both would double-strip.Why
Reasoning models increasingly emit
<think>blocks before their final answer. Without stripping, answer-extraction filters see the whole reasoning chain and mis-score otherwise-correct answers. This gives tasks a one-line opt-in for the standard fix.Open question for maintainers
This overlaps conceptually with the existing
reasoning_tagsmechanism (which rewrites filter keys at scoring time). I kept this as a filter because it composes with per-task pipelines, and gated the two against each other — but happy to consolidate onto one mechanism if you prefer.Test plan
python3 -m py_compileon all changed filesTaskConfig().auto_strip_thinkingdefaults toFalsetest/eval/test_strip_thinking_filter.py): with the filter enabled, a decoy answer inside<think>is ignored and the real answer is extracted by the downstream regex filter;filtered_respscontains no extrastrip_thinkingkey; 99 filter/eval tests passruff checkintroduces zero new findings vs. pre-change baselineReview pass (2026-07-06)
Self-review found the original wiring added the strip step as a sibling filter ensemble — ensembles don't chain, so extraction filters never saw stripped text and the new ensemble's list-shaped output would itself get scored (crashing e.g. MMMU's
process_results). Follow-up commit rewires it to prepend into each existing pipeline (as described above), flips the default to opt-in, adds thereasoning_tagsgating, and documents two known limitations instrip_reasoning_tags(case-sensitive tags; unclosed opening tag passes through).